package org.example.antares.blog.service.impl;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.example.antares.blog.model.dto.article.ArticleEsDTO;
import org.example.antares.blog.model.dto.article.ArticleQueryRequest;
import org.example.antares.blog.model.vo.article.ArticleVo;
import org.example.antares.blog.service.ArticleSearchService;
import org.example.antares.blog.service.ArticleService;
import org.example.antares.common.constant.SystemConstants;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ArticleSearchServiceImpl implements ArticleSearchService {
    @Resource
    private ArticleService articleService;
    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public Page<ArticleVo> searchFromEs(ArticleQueryRequest articleQueryRequest) {
        String keyword = articleQueryRequest.getKeyword();
        List<String> tags = articleQueryRequest.getTags();
        int pageNum = articleQueryRequest.getPageNum();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 过滤
        boolQueryBuilder.filter(QueryBuilders.termQuery("status", SystemConstants.ARTICLE_STATUS_PUBLISHED));

        // 必须包含所有标签
        if (CollectionUtils.isNotEmpty(tags)) {
            for (String tag : tags) {
                boolQueryBuilder.filter(QueryBuilders.termQuery("tags", tag));
            }
        }

        if (StringUtils.isNotBlank(keyword)) {
            boolQueryBuilder.should(QueryBuilders.matchQuery("title", keyword));
            boolQueryBuilder.should(QueryBuilders.matchQuery("summary", keyword));
            boolQueryBuilder.should(QueryBuilders.matchQuery("content", keyword));
            boolQueryBuilder.should(QueryBuilders.matchQuery("createdBy", keyword));
            boolQueryBuilder.minimumShouldMatch(1);
        }

        // 分页（es的起始页为0）
        PageRequest pageRequest = PageRequest.of(pageNum - 1, 10);
        // 构造查询
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
                .withPageable(pageRequest).build();
        SearchHits<ArticleEsDTO> searchHits = elasticsearchRestTemplate.search(searchQuery, ArticleEsDTO.class);
        Page<ArticleVo> page = new Page<>();
        page.setTotal(searchHits.getTotalHits());
        // 查出结果后，从 db 获取最新动态数据（比如点赞数）
        if (searchHits.hasSearchHits()) {
            List<SearchHit<ArticleEsDTO>> searchHitList = searchHits.getSearchHits();
            List<Long> articleIds = searchHitList.stream().map(searchHit -> searchHit.getContent().getId())
                    .collect(Collectors.toList());

            //获取request
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = null;
            if (requestAttributes != null) {
                request = requestAttributes.getRequest();
            }
            // 从数据库中取出更完整的数据
            List<ArticleVo> articleVoList = articleService.getArticlesByIds(articleIds, request);
            if(articleVoList != null) {
                page.setRecords(articleVoList);
            }
        } else {
            page.setRecords(new ArrayList<>());
        }
        return page;
    }
}
